package com.tarena.lbs.marketing.service.impl;

import com.tarena.lbs.attach.api.AttachApi;
import com.tarena.lbs.base.common.utils.Asserts;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.pager.BasePageList;
import com.tarena.lbs.basic.api.AdminApi;
import com.tarena.lbs.basic.api.UserApi;
import com.tarena.lbs.common.passport.enums.Roles;
import com.tarena.lbs.common.passport.principle.UserPrinciple;
import com.tarena.lbs.common.security.utils.LbsSecurityContenxt;
import com.tarena.lbs.marketing.repository.ActivityRepository;
import com.tarena.lbs.marketing.repository.CouponCodeRepository;
import com.tarena.lbs.marketing.repository.CouponRepository;
import com.tarena.lbs.marketing.repository.UserReceiveCouponRepo;
import com.tarena.lbs.marketing.service.CouponService;
import com.tarena.lbs.pojo.attach.dto.AttachQrDTO;
import com.tarena.lbs.pojo.attach.param.AttachQRParam;
import com.tarena.lbs.pojo.basic.dto.AdminDTO;
import com.tarena.lbs.pojo.marketing.bo.CouponBO;
import com.tarena.lbs.pojo.marketing.bo.CouponCodeBO;
import com.tarena.lbs.pojo.marketing.bo.MarketingActivityBO;
import com.tarena.lbs.pojo.marketing.bo.UserReceiveCouponBO;
import com.tarena.lbs.pojo.marketing.param.UserReceiveCouponParam;
import com.tarena.lbs.pojo.marketing.query.CouponQuery;
import com.tarena.lbs.pojo.marketing.query.UserCouponCodeQuery;
import com.tarena.lbs.pojo.marketing.query.UserCouponQuery;
import com.tarena.lbs.stock.api.StockApi;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class CouponServiceImpl implements CouponService {
    @Autowired
    private CouponRepository couponRepository;
    @Autowired
    private AdminApi adminApi;
    @Autowired
    private CouponCodeRepository couponCodeRepository;
    @Autowired
    private StockApi stockApi;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UserReceiveCouponRepo userReceiveCouponRepo;
    @Autowired
    private ActivityRepository activityRepository;
    @Autowired
    private UserApi userApi;
    @Autowired
    private AttachApi attachApi;

    @Override
    public BasePageList<CouponBO> couponPage(CouponQuery query) throws BusinessException {
        //1.获取登录认证
        UserPrinciple userPrinciple=getUserPrinciple();
        //2.获取角色 和id
        Integer adminId = userPrinciple.getId();
        Roles role = userPrinciple.getRole();
        if (role==Roles.USER){
            log.error("用户:{},正在查看优惠卷列表",userPrinciple);
            throw new BusinessException("108","角色不具备权限");
        }
        Integer businessId=null;
        if (role==Roles.SHOP){
            //用户分支 商家id 远程调用获取一个businessId关联
            businessId=getShopBusinessId(adminId);
        }
        //3.调用仓储层查询
        BasePageList<CouponBO> boPages=couponRepository.getCouponPage(query,businessId);
        return boPages;
    }


    //Transactional默认对RuntimeException回滚
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void couponSave(CouponBO bo) throws BusinessException {
        UserPrinciple userPrinciple = getUserPrinciple();
        Integer adminId=userPrinciple.getId();
        //dubbo远程调用获取id对应用户详情
        AdminDTO adminDetail = adminApi.getAdminDetail(adminId);
        if (adminDetail==null){
            throw new BusinessException("109","找不到商家信息");
        }
        bo.setBusinessId(adminDetail.getBusinessId());
        bo.setCreateAt(new Date());
        bo.setUpdateAt(bo.getCreateAt());
        bo.setStatus(0);
        bo.setEnableStatus(0);
        bo.setId(couponRepository.saveCoupon(bo));//coupon
        couponCodeRepository.batchSaveCouponCode(bo);//coupon_code
        //远程调用stock库存的初始化
        initCouponStock(bo);
        //对redis库存做初始化 发行量就是redis当前存储优惠卷的 数字
        String couponStockKey="coupon:stock:"+bo.getId();
        stringRedisTemplate.opsForValue().set(couponStockKey,bo.getMaxUsageLimit()+"");
    }

    @Override
    public CouponBO couponDetail(Integer id) {
        return couponRepository.getCouponById(id);
    }

    @Override
    public void saveUserReceiveCoupon(UserReceiveCouponParam param) throws BusinessException {
        //1. 用户信息 消息中携带
        Integer userId=param.getUserId();
        //2. 查询优惠券详情
        Integer couponId = param.getCouponId();
        CouponBO couponBO = couponRepository.getCouponById(couponId);
        Asserts.isTrue(couponBO==null,new BusinessException("-2","没有优惠券"));
        //3. 查询活动详情 用户群体 在活动管理数据中
        Integer activityId = param.getActivityId();
        MarketingActivityBO activityBO = activityRepository.getActivitiesById(activityId);
        Asserts.isTrue(activityBO==null,new BusinessException("-3","没有活动"));
        //4. 用户领取次数
        Integer usageLimit = couponBO.getUsageLimit();
        //查询当前用户 userId 已经领取优惠 couponId 券记录TODO
        //SELECT * FROM user_receive_coupon where user_id=#{userId} and coupon_id=#{couponId}
        List<UserReceiveCouponBO> receiveBOS= userReceiveCouponRepo.receiveCouponList(userId,couponId);
        Asserts.isTrue(receiveBOS!=null&&receiveBOS.size()>=usageLimit,new BusinessException("-4","领多了"));
        //当我的领取记录 为空说明该用户从来没领过 校验一下符合人群
        if (CollectionUtils.isEmpty(receiveBOS)){
            //5.校验人群 用户--标签  人群--标签 活动--人群 basic
            String groupId = activityBO.getTargetCustomer();//用户人群名称
            boolean isGroup=userApi.isUserGroup(userId,Integer.valueOf(groupId));
            Asserts.isTrue(!isGroup,new BusinessException("-5","不符合人群"));
        }
        //6.扣减库存 未必成功 RPC 调用 这步完成扣减 才是真正的领到了优惠券
        //update coupon_stock set num=num-1 where coupon_id=#{couponId} and num>0;
        boolean result = stockApi.updateCouponNum(couponId);
        Asserts.isTrue(!result,new BusinessException("-2","库存不足"));
        //7.领取优惠券code码,保证是可用的 status=0(未领取) 字符串 TODO coupon_code
        //select * from coupon_code where coupon_id=#{} and status=0
        CouponCodeBO couponCodeBO=couponCodeRepository.getAvailableCouponCode(couponId);
        //8.记录领取 user_receive_coupon数据
        //补全param
        param.setCouponCode(couponCodeBO.getCouponCode());
        UserReceiveCouponBO userReceiveCouponBO=new UserReceiveCouponBO();
        BeanUtils.copyProperties(param,userReceiveCouponBO);
        userReceiveCouponBO.setCouponName(couponBO.getCouponName());
        userReceiveCouponBO.setCouponType(couponBO.getCouponType());
        userReceiveCouponBO.setCouponValue(couponBO.getDiscountValue());
        userReceiveCouponBO.setCreateAt(new Date());
        userReceiveCouponBO.setStatus(0);
        //insert into user_receive_coupon (全字段) values(#{属性})
        userReceiveCouponRepo.saveUserReceiveCoupon(userReceiveCouponBO);
        //9.修改一下 领到的coupon_code status=1(已领取)
        //update coupon_code set status=1 where id=#{id};
        couponCodeRepository.updateReceivedById(couponCodeBO);
    }

    @Override
    public BasePageList<UserReceiveCouponBO> userReceivePage(UserCouponQuery query) throws BusinessException {
        UserPrinciple userPrinciple = getUserPrinciple();
        query.setUserId(userPrinciple.getId());
        return userReceiveCouponRepo.userReceivePage(query);
    }


    @Override
    public UserReceiveCouponBO userReceiveDetail(UserCouponCodeQuery query) throws BusinessException {
        //1.使用code某一个优惠券码 查询一个领取记录详情
        UserReceiveCouponBO bo=userReceiveCouponRepo.getUserReceiveDetail(query.getCouponCode());
        Asserts.isTrue(bo==null,new BusinessException("-2","没有领取记录"));
        //2.走缓存流程 存储的就是codeUrl code做key url做value
        String codeKey="user:coupon:code:url:"+query.getCouponCode();
        String codeUrl = stringRedisTemplate.opsForValue().get(codeKey);
        if (StringUtils.isNotEmpty(codeUrl)){
            //非空 命中 封装返回
            bo.setCouponUrl(codeUrl);
        }else{
            //空 未命中 调用attach生成 携带http://www.baidu.com?code=券码
            AttachQRParam qrParam=new AttachQRParam();
            qrParam.setContent("http://www.baidu.com?code="+query.getCouponCode());
            //绑定当前优惠券 couponCodeId 500
            qrParam.setBusinessType(500);//表示业务是某个优惠券中的一个券码
            qrParam.setBusinessId(bo.getId());
            AttachQrDTO attachQrDTO = attachApi.generateQrCode(qrParam);
            String url = attachQrDTO.getUrl();//http://localhost:9081/static/093hd0932hr032jrt-0.png
            //缓存填补数据
            stringRedisTemplate.opsForValue().set(codeKey,url);
            bo.setCouponUrl(url);
        }
        return bo;
    }

    private void initCouponStock(CouponBO bo) throws BusinessException {
        boolean result = stockApi.initCouponStock(bo.getId(), bo.getMaxUsageLimit());
        if (!result){
            throw new BusinessException("110","远程调用生成库存失败");
        }
    }

    private Integer getShopBusinessId(Integer adminId) throws BusinessException{
        log.info("当前登录用户为SHOP角色,调用远程查询adminId:{}",adminId);
        AdminDTO adminDetail = adminApi.getAdminDetail(adminId);
        if (adminDetail == null){
            throw new BusinessException("109","找不到商家信息");
        }
        return adminDetail.getBusinessId();
    }

    //解析jwt
    private UserPrinciple getUserPrinciple() throws BusinessException {
        UserPrinciple userPrinciple = LbsSecurityContenxt.getLoginToken();
        if (userPrinciple == null){
            throw new BusinessException("101","用户认证解析失败");
        }
        return userPrinciple;
    }
}
